package com.liuch.mybatis.binding;

import com.google.common.collect.Maps;
import com.liuch.demo.entity.User;
import com.liuch.mybatis.Utils.ResultSet2List;
import com.liuch.mybatis.annotations.Param;
import com.liuch.mybatis.annotations.Select;
import com.liuch.mybatis.parsing.GenericTokenParser;
import com.liuch.mybatis.parsing.ParameterMappingTokenHandler;
import com.liuch.mybatis.type.IntegerTypeHandler;
import com.liuch.mybatis.type.StringTypeHandler;
import com.liuch.mybatis.type.TypeHandler;
import lombok.SneakyThrows;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;

/**
 * mapper代理
 */
public class MapperProxy implements InvocationHandler {

    private Map<Class, TypeHandler> typeHandlerMap = Maps.newHashMap();

    public MapperProxy(){
        typeHandlerMap.put(Integer.class, new IntegerTypeHandler());
        typeHandlerMap.put(String.class, new StringTypeHandler());

    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Connection conn = getConnection();

        //拿到sql
         Select select = method.getAnnotation(Select.class);
         String originalSql = select.value();

         //sql解析
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "" +
                "}", parameterMappingTokenHandler);
        String sql = genericTokenParser.parse(originalSql);
        List<String> parameterMappings = parameterMappingTokenHandler.getParameterMappings();

        //构建sql&执行
        PreparedStatement ps = conn.prepareStatement(sql);

        // 获取mapper调用方法的参数名和对应的参数值
        Map<String, Object> paramValueMap = Maps.newHashMap();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Param param = parameter.getAnnotation(Param.class);
            String paramName = param.value();
            paramValueMap.put(paramName, args[i]);
        }

        //设置值
        for (int i = 0; i < parameterMappings.size(); i++) {
            String jdbcColumnName = parameterMappings.get(i);
            Object val = paramValueMap.get(jdbcColumnName);
            this.typeHandlerMap.get(val.getClass()).setParameter(ps, i+1, val);
            //ps.setObject(i+1, val);
        }

//        ps.setInt(1, (Integer)args[0]);
//        ps.setString(2, String.valueOf(args[1]));

        ps.execute();
        ResultSet rs = ps.getResultSet();

        return ResultSet2List.resultSetToList(rs, User.class);
    }

    @SneakyThrows
    public static Connection getConnection(){
        //加载JDBC驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //建立连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis_hand?useUnicode=true&characterEncoding=utf-8", "root", "123456");

        return conn;
    }


}
